package com.cynteka.cyfoman.ui;

import com.cynteka.cyfoman.core.RefItem;
import com.cynteka.cyfoman.core.Util;
import com.cynteka.cyfoman.core.ValueObject;
import com.cynteka.cyfoman.core.config.*;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: Sergey
 * Date: 03.08.11
 * Time: 13:53
 */
public class StoreListener implements IEventListener {

    private static Logger logger = Logger.getLogger(StoreListener.class.getName());
    private DataSource dataSource;

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void handleEvent(IEvent event) {
        if (event instanceof StoreEvent) {
            StoreEvent storeEvent = (StoreEvent) event;
            ValueObject valueObject = storeEvent.getValueObject();
            ActionMD actionMD = storeEvent.getAction();

            if (actionMD.getTable() != null && !"".equals(actionMD.getTable())) {
                Connection connection = null;
                String query = null;
                try {
                    connection = dataSource.getConnection();

                    if (valueObject.getId() == null) {
                        query = Util.generateInsertQuery(actionMD);
                    } else {

                        query = Util.generateUpdateQuery(actionMD);
                    }

                    connection.setAutoCommit(false);

                    PreparedStatement statement = connection.prepareStatement(query);
                    int idx = 1;
                    for (ParamMD param : actionMD.getActionParams()) {
                        Object value = valueObject.getParam(param);
                        if (value instanceof RefItem) {
                            RefItem refItem = (RefItem) value;
                            value = refItem.id;
                        }
                        if (param.getParamType() == ParamType.COLLECTION) {
                            // process another table
                            break;
                        }
                        if (value == null) {
                            // TODO just for debug
                            System.currentTimeMillis();
                        }
                        statement.setObject(idx, value);
                        idx++;
                    }
                    if (valueObject.getId() != null) {
                        statement.setObject(idx, valueObject.getId());
                        idx++;
                    }
                    statement.execute();

                    if (valueObject.getId() == null) {

                        statement = connection.prepareStatement("select last_insert_id()");
                        ResultSet rs = statement.executeQuery();
                        rs.next();
                        int id = rs.getInt(1);
                        valueObject.setId(id);
                    }


                    for (ParamMD param : actionMD.getActionParams()) {
                        if (param.getParamType() == ParamType.COLLECTION) {
                            // Collections
                            // clear previous
                            CollectionMD collectionMD = param.getCollection();
                            query = String.format("delete from %1s where %2s = ?", collectionMD.getCrossTable(), collectionMD.getReferenceFromField());
                            statement = connection.prepareStatement(query);
                            statement.setObject(1, valueObject.getId());
                            statement.execute();

                            query = String.format("insert into %1s (%2s, %3s) values(?,?)", collectionMD.getCrossTable(), collectionMD.getReferenceFromField(), collectionMD.getReferenceToField());
                            statement = connection.prepareStatement(query);

                            Collection<RefItem> refItems = (Collection<RefItem>) valueObject.getParam(param);
                            for (RefItem refItem : refItems) {
                                statement.setObject(1, valueObject.getId());
                                statement.setObject(2, refItem.id);
                                statement.execute();
                            }
                        }
                    }

                    connection.commit();
                } catch (SQLException e) {
                    logger.log(Level.SEVERE, "Can not execute statement " + query, e);
                    try {
                        connection.rollback();
                    } catch (SQLException e1) {
                        logger.log(Level.SEVERE, "Can not rollback transaction " + query, e);
                    }
                } finally {
                    if (connection != null) {
                        try {
                            connection.close();
                        } catch (SQLException e) {
                            logger.log(Level.SEVERE, "Can not close connection", e);
                        }
                    }
                }

            }
        }
    }
}
